package se.sics.drsm.simulation;

import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.sics.drsm.model.SONConfiguration;
import se.sics.drsm.simulation.events.DRSMSimulatorInit;
import se.sics.drsm.simulation.ports.DRSMSimulationPort;
import se.sics.kompics.*;
import se.sics.kompics.address.Address;
import se.sics.kompics.network.Network;
import se.sics.kompics.p2p.bootstrap.BootstrapConfiguration;
import se.sics.kompics.p2p.experiment.dsl.SimulationScenario;
import se.sics.kompics.p2p.fd.ping.PingFailureDetectorConfiguration;
import se.sics.kompics.p2p.monitor.chord.server.ChordMonitorConfiguration;
import se.sics.kompics.p2p.simulator.P2pSimulator;
import se.sics.kompics.p2p.simulator.P2pSimulatorInit;
import se.sics.kompics.simulation.SimulatorScheduler;
import se.sics.kompics.timer.Timer;

import java.io.IOException;
import java.net.InetAddress;


public final class SimulationContainerMain extends ComponentDefinition {
    static {
        PropertyConfigurator.configureAndWatch("log4j.properties");
    }

    private static final Logger logger = LoggerFactory
            .getLogger(SimulationContainerMain.class);

    private static SimulatorScheduler simulatorScheduler;
    private static SimulationScenario scenario;

    public static void main(String[] args) {
        simulatorScheduler = new SimulatorScheduler();
        scenario = SimulationScenario.load(System.getProperty("scenario"));
        Kompics.setScheduler(simulatorScheduler);
        Kompics.createAndStart(SimulationContainerMain.class, 1);
    }

    public SimulationContainerMain() throws IOException {
        P2pSimulator.setSimulationPortType(DRSMSimulationPort.class);

        //TODO: reuse or remove
//		long pid = LaunchUtil.BOOT_PID;

        // create
        Component p2pSimulator = create(P2pSimulator.class);
        Component drsmSimulator = create(DRSMSimulator.class);


        // loading component configurations
        BootstrapConfiguration bconfiguration = BootstrapConfiguration.load("bootstrap.properties");
        SONConfiguration chordConfiguration = SONConfiguration.load("chord.properties");
        PingFailureDetectorConfiguration failureDetectorConfiguration = PingFailureDetectorConfiguration.load("failure_detector.properties");
        ChordMonitorConfiguration chordMonitorConfiguration = ChordMonitorConfiguration.load("chord_monitor.properties");

        long SEED = Long.parseLong(System.getProperty("cats.seed", "0"));
//		FIXME
//		GlobalView.reset(catsCfg);
//		Metrics.reset();
        logger.debug("SEED={}", SEED);
//		logger.debug("Starting simulation with boot threshold={}", bootCfg.THRESHOLD);
        logger.debug("Property bootstrap.nodes.threshold={}",
                System.getProperty("bootstrap.nodes.threshold"));

        trigger(new P2pSimulatorInit(simulatorScheduler, scenario,
//				new KingLatencyMap(SEED)), p2pSimulator.getControl());
                new SimplifiedNetworkModel(SEED, 89)), p2pSimulator.getControl());

        Address localAddress = new Address(InetAddress.getLocalHost(), 46000, 5);
        trigger(new DRSMSimulatorInit(localAddress, null, bconfiguration, chordConfiguration, chordMonitorConfiguration),
                drsmSimulator.control()); // take random from simulation scenario

        // connect
        connect(drsmSimulator.getNegative(Network.class), p2pSimulator
                .getPositive(Network.class));
        connect(drsmSimulator.getNegative(Timer.class), p2pSimulator
                .getPositive(Timer.class));
        connect(drsmSimulator.getNegative(DRSMSimulationPort.class), p2pSimulator
                .getPositive(DRSMSimulationPort.class));

        subscribe(faultHandler, p2pSimulator.control());
        subscribe(faultHandler, drsmSimulator.control());
    }


    Handler<Fault> faultHandler = new Handler<Fault>() {
        public void handle(Fault event) {
            logger.error("Fault: {}", event.getFault());
            event.getFault().printStackTrace();
//			Metrics.dumpError();
//			GlobalView.shutdown();
            Kompics.shutdown();
        }
    };
}
